#include "SimpleReadTest.h"

#include <QCoreApplication>
#include <QSerialPort>
#include <QTcpSocket>
#include <QHostAddress>
#include <QTimer>

#include <iostream>
using namespace std;

#include "impl/ConsoleTrace.h"

/**
 * @brief SimpleReadTest::SimpleReadTest    Constructor
 * @param parent    If available the parent object
 */
SimpleReadTest::SimpleReadTest(QObject *parent) : QObject(parent)
{

}

/**
 * @brief SimpleReadTest::init  Initializes the protocol handler with a seriel port
 * @param serialPort    The name of the serial port
 */
void SimpleReadTest::init(QString serialPort)
{
    // Open serial port
    QSerialPort* port = new QSerialPort();
    port->setPortName(serialPort);
    port->setFlowControl(QSerialPort::NoFlowControl);
    port->setParity(QSerialPort::NoParity);
    port->setDataBits(QSerialPort::Data8);
    port->setStopBits(QSerialPort::OneStop);
    port->setBaudRate(QSerialPort::Baud115200);
    if(!port->open(QIODevice::ReadWrite))
    {
        print("Could not open the serial port " + serialPort);
        delete port;
        return;
    }

    init(port);
}

/**
 * @brief SimpleReadTest::init  Initializes the protocol handler with a TCP port
 * @param ip    IP address of the reader
 * @param port  TCP Port of the reader
 */
void SimpleReadTest::init(QString ip, ushort port)
{
    // Open socket
    QTcpSocket* sock = new QTcpSocket();
    sock->connectToHost(QHostAddress(ip), port);
    if(!sock->waitForConnected())
    {
        print("Could not connect to " + ip + ":" + QString::number(port));
        delete sock;
        return;
    }

    init(sock);
}

/**
 * @brief SimpleReadTest::init  Initializes the protocol handler
 * @param dev   IO Device of the data connection to the reader
 */
void SimpleReadTest::init(QIODevice *dev)
{
    // Create Tracer
    m_trc = new ConsoleTrace();
    QrfeReaderInterface::Global::m_tracer = m_trc;
    QrfeReaderInterface::Global::m_tracer->setTraceLevel(1);

    // Create Protocol Handler
    m_ph = new QrfeReaderInterface::QrfeProtocolHandler(dev);
    m_ph->setHeartBeat(QrfeReaderInterface::HEARTBEAT_OFF);

    // Connect signals
    connect(m_ph, SIGNAL(heartBeat()),
            this,   SLOT(heartBeat()));
    connect(m_ph, SIGNAL(cyclicInventory(QrfeReaderInterface::QrfeTagEvent)),
            this,   SLOT(cyclicInventory(QrfeReaderInterface::QrfeTagEvent)));

    // Call start function from event loop after 100ms
    QTimer::singleShot(100, this, SLOT(start()));
}

/**
 * @brief SimpleReadTest::start Starts the test
 */
void SimpleReadTest::start()
{
    // Reset counters
    m_cyclicInvCount = 0;
    m_cyclicInvTime.start();

    // Start cyclic inventory
    m_ph->setCyclicInventory(true);

    // Print start
    print("\t -> Started Cyclic Inventry");

    // Call stop funtion after 5 seconds
    QTimer::singleShot(5000, this, SLOT(stop()));
}

/**
 * @brief SimpleReadTest::stop Stops the test
 */
void SimpleReadTest::stop()
{
    // Stop cyclic inventory
    m_ph->setCyclicInventory(false);

    // Calculate and print read rate
    double readRate = (double)m_cyclicInvCount / ((double)m_cyclicInvTime.elapsed()/1000.0);
    print("\t -> Stopped Cyclic Inventry with a ReadRate of " + QString::number(readRate) + " reads/sec");

    // Quit application
    qApp->quit();
}


/**
 * @brief SimpleReadTest::heartBeat Slot for the heartbeat event
 */
void SimpleReadTest::heartBeat ()
{
    uint elapsed = m_heartBeatTime.elapsed();
    m_heartBeatTime.start();
    print("\t[E] Heartbeat after " + QString::number(elapsed));
}

/**
 * @brief SimpleReadTest::cyclicInventory   Slot for the cyclic inventory event
 * @param tagInfo   The info of the detected tag
 */
void SimpleReadTest::cyclicInventory (const QrfeReaderInterface::QrfeTagEvent &tagInfo)
{
    QString info;
    info = "\t[E] " + QString("%1").arg(++m_cyclicInvCount, 8, 10, QChar(' ')) + " " + tagInfo.tagId.toHex() + " ";

    if (tagInfo.hasMemory)
    {
        info += " MEM@" + QString::number(tagInfo.memBank) + "." + QString::number(tagInfo.memAddr) + ":" + tagInfo.memData.toHex() + " ";
    }

    if (tagInfo.hasApplicationInfo)
    {
        info += " APP:" + tagInfo.applicationInfo.toHex() + " ";
    }

    print(info);

    if (tagInfo.hasRSSI)
    {
        QString q_str;
        q_str = "\t\t\tQ: ";
        for (int i = 0; i < tagInfo.rssi[0]; i++)
            q_str.append("#");
        print(q_str);

        QString i_str;
        i_str = "\t\t\tI: ";
        for (int i = 0; i < tagInfo.rssi[1]; i++)
            i_str.append("#");
        print(i_str);
    }
}

/**
 * @brief SimpleReadTest::print     Print out the given string
 * @param str   The string to print
 */
void SimpleReadTest::print(const QString &str)
{
    cout << str.toLatin1().data() << endl;
}
